package cn.zcy.jdb;

import cn.zcy.handler.ResultSetHandler;

import javax.sql.DataSource;
import java.sql.*;

/**
 * 自定义JdbcTemplate
 */
public class ZcyJdbcTemplate {

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public ZcyJdbcTemplate() {

    }

    public ZcyJdbcTemplate(DataSource dataSource) {
        setDataSource(dataSource);
    }

    /**
     * 用于执行增删改放啊
     *
     * @param sql    执行sql语句
     * @param params 执行sql语句所需要的参数
     * @return 返回执行sql之后影响的行数
     */
    public int update(String sql, Object... params) {
        //1.验证数据源是否有只
        if (dataSource == null) {
            throw new NullPointerException("DataSource can not be null !");
        }

        //2.定义JDBC操作相关的对象
        Connection coon = null;
        PreparedStatement pst = null;
        int res = 0;

        try {
            //3.获取连接
            coon = dataSource.getConnection();

            //4.获取预处理对象 (传递sql语句)
            pst = coon.prepareStatement(sql);
            //5.获取参数的源信息
            ParameterMetaData pmd = pst.getParameterMetaData();
            //6.获取sql语句中参数的个数
            int parameterCount = pmd.getParameterCount();

            //7.判断sql语句中是否有参数
            if (parameterCount > 0) {
                //判断是否提供了参数
                if (params == null) {
                    throw new IllegalArgumentException("params can not be null");
                }
                //判断参数个数是否匹配
                if (parameterCount != params.length) {
                    throw new IllegalArgumentException("Incorrect parameterCount size: expected" + String.valueOf(parameterCount) + "but" + String.valueOf(params.length));
                }
                //检验参数通过，给占位符赋值
                for (int i = 0; i < parameterCount; i++) {
                    pst.setObject(i + 1, params[i]);
                }
            }
            //8.执行sql语句
            res = pst.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(null, pst, coon);
        }
        return res;
    }

    /**
     * 用于执行查询方法
     *
     * @param sql    执行sql语句
     * @param rsh    处理结果结的分装，此处之提供一个规范（由使用自己编写具体实现））
     * @param params 执行sql语句所需要的参数
     * @return 返回查询结果
     */
    public Object query(String sql, ResultSetHandler rsh, Object...params) {
        //1.验证数据源是否有只
        if (dataSource == null) {
            throw new NullPointerException("DataSource can not be null !");
        }

        //2.定义JDBC操作相关的对象
        Connection coon = null;
        PreparedStatement pst = null;
        ResultSet res = null;

        try {
            //3.获取连接
            coon = dataSource.getConnection();

            //4.获取预处理对象 (传递sql语句)
            pst = coon.prepareStatement(sql);
            //5.获取参数的源信息
            ParameterMetaData pmd = pst.getParameterMetaData();
            //6.获取sql语句中参数的个数
            int parameterCount = pmd.getParameterCount();

            //7.判断sql语句中是否有参数
            if (parameterCount > 0) {
                //判断是否提供了参数
                if (params == null) {
                    throw new IllegalArgumentException("params can not be null");
                }
                //判断参数个数是否匹配
                if (parameterCount != params.length) {
                    throw new IllegalArgumentException("Incorrect parameterCount size: expected" + String.valueOf(parameterCount) + "but" + String.valueOf(params.length));
                }
                //检验参数通过，给占位符赋值
                for (int i = 0; i < parameterCount; i++) {
                    pst.setObject(i + 1, params[i]);
                }
            }
            //8.执行sql语句
            res = pst.executeQuery();
            return rsh.handle(res);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            close(res, pst, coon);
        }

    }

    /**
     * 释放资源的方法
     *
     * @param resultSet
     * @param pst
     * @param connection
     */
    private void close(ResultSet resultSet, PreparedStatement pst, Connection connection) {

        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        try {
            if (pst != null) {
                pst.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }


        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
